<!DOCTYPE html>


<html lang="zh-CN">


<head>
  <meta charset="utf-8" />
    
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
    分享Linux内存占用几个案例.md |  
  </title>
  <meta name="generator" content="hexo-theme-ayer">
  
  <link rel="shortcut icon" href="/favicon.ico" />
  
  
<link rel="stylesheet" href="/dist/main.css">

  
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css">

  
<link rel="stylesheet" href="/css/custom.css">

  
  
<script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>

  
  

  

</head>

</html>

<body>
  <div id="app">
    
      
    <main class="content on">
      <section class="outer">
  <article
  id="post-linux/分享Linux内存占用几个案例"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  分享Linux内存占用几个案例.md
</h1>
 

    </header>
     
    <div class="article-meta">
      <a href="/2020/11/11/linux/%E5%88%86%E4%BA%ABLinux%E5%86%85%E5%AD%98%E5%8D%A0%E7%94%A8%E5%87%A0%E4%B8%AA%E6%A1%88%E4%BE%8B/" class="article-date">
  <time datetime="2020-11-10T16:00:00.000Z" itemprop="datePublished">2020-11-11</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/linux/">linux</a>
  </div>
  
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> 字数统计:</span>
            <span class="post-count">3k</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> 阅读时长≈</span>
            <span class="post-count">11 分钟</span>
        </span>
    </span>
</div>
 
    </div>
      
    <div class="tocbot"></div>




  
    <div class="article-entry" itemprop="articleBody">
       
  <h1 id="分享Linux内存占用几个案例"><a href="#分享Linux内存占用几个案例" class="headerlink" title="分享Linux内存占用几个案例"></a>分享Linux内存占用几个案例</h1><h2 id="案例一"><a href="#案例一" class="headerlink" title="案例一"></a>案例一</h2><h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><p>最近一台 <code>CentOS</code> 服务器，发现内存无端<code>损失</code>了许多，<code>free</code> 和 <code>ps</code> 统计的结果<code>相差十几个G</code>，非常奇怪，后来Google了许久才搞明白。</p>
<h3 id="分析"><a href="#分析" class="headerlink" title="分析"></a>分析</h3><p>1、linux系统内存消耗主要有三个地方：</p>
<ul>
<li>进程</li>
<li>slab</li>
<li>pagecacge</li>
</ul>
<p>用 <code>free</code> 命令查看到的是系统整体的内容使用情况，而使用 <code>ps</code> 和 <code>top</code> 看到的内存使用情况都是以进程维度来看的，因此看不到 <code>slabcache</code> <code>和pagecache</code> 的内存占用信息。</p>
<p>2、判断应用程序是否有内存泄露问题，只根据进程的内存使用或机器的内存变化来判定都不太准确，如果单凭进程的内存变化可能会疏忽一些小对象的内存泄露问题。</p>
<p>同时对于机器的内存的使用也要做是否合理的判断。对于不同语言的应用都有相应的神器可以辅助定位内存泄露问题，同时结合linux内存的监控工具进行分析， 除了 <code>top</code>，<code>free</code>还有 <code>pmap</code>，<code>/proc/meminfo</code> 和 <code>/slabinfo</code>，<code>slaptop</code>等。</p>
<p>3、通过这个问题，有一点比较重要的是，在使用监控工具进行监控和分析时，对其值的具体含义还是要了解的很清楚，否则会造成误判，使问题变得更加复杂。</p>
<p>4、此外 <code>page cache</code>，<code>dentries</code>和<code>inodes cache</code>，系统是会自动回收的。</p>
<p>可以通过以下几种方式加速其回收，不过实际并不需要这么做。</p>
<p>手工清除内存 缓存</p>
<ul>
<li><code>echo 1 &gt; /proc/sys/vm/drop_caches</code> 清除page cache</li>
<li><code>echo 2 &gt; /proc/sys/vm/drop_caches</code> 清除denries和inodes</li>
<li><code>echo 3 &gt; /proc/sys/vm/drop_caches</code> 清除page cache ，dentries及inodes</li>
<li>调整 <code>vm.vfs_cache_pressure</code> 值大小，默认是100。值越大，dentries和inodes cache的回收速度会越快</li>
<li>调整 <code>vm.min_free_kbytes</code> 值大小，该值为系统开始内存回收的阀值，越大表示系统会越早开始回收(一般情况下此值不建议调整)。</li>
</ul>
<h3 id="问题描述和初步调查"><a href="#问题描述和初步调查" class="headerlink" title="问题描述和初步调查"></a>问题描述和初步调查</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ free -g</span><br></pre></td></tr></table></figure>

<p><img src="http://iubest.gitee.io/pic/640-1601003514378.png" alt="img"></p>
<p>这台服务器有 <code>16G内存</code>，但是结果显示除了2G左右的文件Buffer缓存外，其余十几G都被确确实实的用光了。(free按1024进制计算，总内存可能比实际偏小)</p>
<p>这里大概介绍下 <code>free</code> 结果的含义:</p>
<p><img src="http://iubest.gitee.io/pic/640-1601003514424.png" alt="img"></p>
<p>然后 <code>top</code> 看了下，没有特别吃内存的程序。用 <code>ps</code> 大概统计下所有程序占用的总内存:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ echo &#96;ps aux |awk &#39;&#123;mem +&#x3D; $6&#125; END &#123;print mem&#x2F;1024&#x2F;1024&#125;&#39;&#96; GB</span><br><span class="line"></span><br><span class="line">0.595089</span><br></pre></td></tr></table></figure>

<p>结果显示所有进程占用的内存还不到 <code>1G</code>，实际上，因为<code>free</code>, <code>ps</code>的统计方式的差别和<code>Copy-on-write</code> 和 <code>Shared libraries</code>等内存优化机制的存在，这两者的统计结果通常是不一样的。但是一般情况下绝对不会相差十几个G，肯定是有什么隐藏的问题，Google了许久后发现，free没有专门统计另一项缓存: <code>Slab</code>。</p>
<h3 id="Slab-简介和进一步调查"><a href="#Slab-简介和进一步调查" class="headerlink" title="Slab 简介和进一步调查"></a>Slab 简介和进一步调查</h3><p><code>Slab Allocation</code> 是Kernel 2.2之后引入的一个内存管理机制，专门用于缓存内核的数据对象，可以理解为一个内核专用的对象池，可以提高系统性能并减少内存碎片。(Kernel 2.6.23之后，SLUB成为了默认的allocator)</p>
<h4 id="查看Slab缓存"><a href="#查看Slab缓存" class="headerlink" title="查看Slab缓存"></a>查看Slab缓存</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">$ cat &#x2F;proc&#x2F;meminfo</span><br><span class="line"></span><br><span class="line"># 其中，Slab相关的数据为</span><br><span class="line">Slab: 154212 kB</span><br><span class="line">SReclaimable: 87980 kB</span><br><span class="line">SUnreclaim: 66232 kB</span><br></pre></td></tr></table></figure>

<p>SReclaimable(Linux 2.6.19+) 都是 clean 的缓存，随时可以释放。回到之前的内存问题，</p>
<h4 id="查看服务器上Slab占用的内存："><a href="#查看服务器上Slab占用的内存：" class="headerlink" title="查看服务器上Slab占用的内存："></a>查看服务器上Slab占用的内存：</h4><p>方法1：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ cat &#x2F;proc&#x2F;meminfo|grep Slab</span><br><span class="line"></span><br><span class="line">Slab: 12777668 kB</span><br></pre></td></tr></table></figure>

<p>方法2：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">echo &#96;cat &#x2F;proc&#x2F;meminfo|grep Slab|awk &#39;&#123;mem +&#x3D; $2&#125; END &#123;print mem&#x2F;1024&#x2F;1024&#125;&#39;&#96; GB</span><br><span class="line"></span><br><span class="line">12G</span><br></pre></td></tr></table></figure>

<p><code>12G</code>的Slab缓存，有意思的是free把Slab缓存统计到了 <code>usedmemory</code> 中，这就是之前那个问题的症结所在了。另外，还可以查看 <code>/proc/slabinfo</code> (或使用 <code>slabtop</code> 命令)来查看Slab缓存的具体使用情况。</p>
<p>结果发现，<code>ext3_inode_cache</code> 和 <code>dentry_cache</code> 占用了绝大部分内存。考虑到这台服务器会频繁地用 <code>rsync</code> 同步大量的文件，这个结果也并不意外。</p>
<h3 id="解决问题"><a href="#解决问题" class="headerlink" title="解决问题"></a>解决问题</h3><p>先说明一下，如果问题仅仅是Slab占用了太多的内存(SReclaimable)，那么通常不需要太操心，因为这根本不是个问题(如果是SUnreclaim太多且不断增长，那么很有可能是内核有bug)。但是，如果是因为Slab占用内存太多而引起了其他的问题，建议继续往下阅读。</p>
<h4 id="清除Slab可回收缓存"><a href="#清除Slab可回收缓存" class="headerlink" title="清除Slab可回收缓存"></a>清除Slab可回收缓存</h4><p>通过 <code>/proc/sys/vm/drop_caches</code> 这个配置项，可以手动清除指定的可回收缓存(SReclaimable)</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">echo 2 &gt; &#x2F;proc&#x2F;sys&#x2F;vm&#x2F;drop_caches&#96; 或者 &#96;sysctl vm.drop_caches&#x3D;2</span><br></pre></td></tr></table></figure>

<p>上面的命令会主动释放 <code>Slab</code> 中 <code>clean的缓存</code>(包括inode和dentry的缓存)，然后再 <code>free -g</code> 一下，空闲的内存陡增了十几个G</p>
<p><code>注意的是</code>，手动清除缓存可能会在一段时间内降低系统性能。原则上不推荐这么做，因为如果有需要，系统会自动释放出内存供其他程序使用。另外，手动清除Slab缓存是一个治标不治本的办法。因为问题不在Slab，实际操作的时候发现，清除缓存一段时间后，<code>Slab缓存</code>很快又会反弹回去。</p>
<p>如果需要治本，要么搞定问题进程，要么修改系统配置，要么增加物理内存。</p>
<h3 id="调整系统-vm-配置"><a href="#调整系统-vm-配置" class="headerlink" title="调整系统 vm 配置"></a>调整系统 vm 配置</h3><blockquote>
<p><code>风险预警</code>: 调整以下系统配置可能会对系统性能造成负面影响，请仔细测试并谨慎操作。</p>
</blockquote>
<p><code>/etc/sysctl.conf</code> 里有以下几个对内存管理影响比较大的内核参数配置：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vm.vfs_cache_pressure</span><br></pre></td></tr></table></figure>

<p>系统在进行内存回收时，会先回收page cache, inode cache, dentry cache和swap cache。vfs_cache_pressure 越大，每次回收时，inode cache和dentry cache所占比例越大。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vfs_cache_pressure</span><br></pre></td></tr></table></figure>

<p>默认是100，该值越大inode cache和dentry cache的回收速度会越快，越小则回收越慢，为0的时候完全不回收，内存溢出(OOM!)。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vm.min_free_kbytes</span><br></pre></td></tr></table></figure>

<p>系统的”保留内存”的大小，”保留内存”用于低内存状态下的”atomic memory allocation requests”(eg. kmalloc + GFP_ATOMIC)，该参数也被用于计算开始内存回收的阀值，默认在开机的时候根据当前的内存计算所得，越大则表示系统会越早开始内存回收。<code>vm.min_free_kbytes 过大可能会导致 OOM</code>，太小可能会导致系统出现死锁等问题。查看默认设置：<code>cat /proc/sys/vm/min_free_kbytes</code></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vm.swappiness</span><br></pre></td></tr></table></figure>

<p>该配置用于控制系统将内存 <code>swap out</code> 到交换空间的积极性，取值范围是[0, 100]。<code>vm.swappiness</code> 越大，系统的交换积极性越高，默认是60， 如果为0则不会进行交换。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ vim &#x2F;etc&#x2F;sysctl.conf</span><br><span class="line"></span><br><span class="line">vm.swappiness &#x3D; 1</span><br></pre></td></tr></table></figure>

<p>查看默认设置：<code>cat /proc/sys/vm/swappiness</code></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">drop_caches</span><br></pre></td></tr></table></figure>

<p>默认值为0，将此值设置为1，2或3，使内核删除页面缓存和slab缓存的各种组合。</p>
<ul>
<li>1 系统使所有的页面缓冲存储器失效并释放。</li>
<li>2 系统释放所有未使用的slab缓存内存。</li>
<li>3 系统释放所有的页面缓存和slab缓存内存。</li>
</ul>
<p>查看默认设置：<code>cat /proc/sys/vm/drop_caches</code></p>
<blockquote>
<p>注：以上参数设置是非破坏性的操作，由于脏数据不能被释放，建议设置以上参数的值之前运行sync把内存数据写入硬盘。在生产环境中不建议使用drop_caches释放内存。</p>
</blockquote>
<h2 id="案例二-（物理内存的外碎片回收）"><a href="#案例二-（物理内存的外碎片回收）" class="headerlink" title="案例二 （物理内存的外碎片回收）"></a>案例二 （物理内存的外碎片回收）</h2><h3 id="问题-1"><a href="#问题-1" class="headerlink" title="问题"></a>问题</h3><p>执行 <code>docker ps</code> 命令挂住</p>
<h3 id="问题分析"><a href="#问题分析" class="headerlink" title="问题分析"></a>问题分析</h3><p>查找 <code>/var/log/messages</code>，发现有错误信息：<code>XFS: possible memory allocation deadlock in kmem_alloc (mode:0x250)</code></p>
<p>在linux中使用<code>buddy算法</code>解决<code>物理内存</code>的<code>碎片问题</code>，其把所有空闲的内存，以2的幂次方的形式，分成11个块链表，分别对应为1、2、4、8、16、32、64、128、256、512、1024个页块。</p>
<p>Linux支持<code>NUMA技术</code>，对于NUMA设备，NUMA系统的结点通常是由一组CPU和本地内存组成，每一个节点都有相应的本地内存，因此buddyinfo 中的Node0表示节点ID；而每一个节点下的内存设备，又可以划分为多个内存区域(zone)，因此下面的显示中，对于Node0的内存，又划分类<code>DMA</code>、<code>Normal</code>、<code>HighMem</code>区域。而后面则是表示空闲的区域。</p>
<p>此处以 <code>Normal</code> 区域进行分析，第二列值为100，表示当前系统中normal区域，可用的连续两页的内存大小为100<em>2</em>PAGE_SIZE；第三列值为52，</p>
<p>表示当前系统中normal区域，可用的连续四页的内存大小为 <code>52*2^2* PAGE_SIZE</code></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ cat &#x2F;proc&#x2F;buddyinfo</span><br><span class="line"></span><br><span class="line">Node 0, zone DMA 23 15 4 5 2 3 3 2 3 1 0</span><br><span class="line">Node 0, zone Normal 149 100 52 33 23 5 32 8 12 2 59</span><br><span class="line">Node 0, zone HighMem 11 21 23 49 29 15 8 16 12 2 142</span><br></pre></td></tr></table></figure>

<p>可以看到从第5列开始，只剩下 <code>44*16*PAGE_SIZE</code> 的页块，后面剩下的分别是<code>1 * 32 *PAGE_SIZE</code>, <code>1 * 64 *PAGE_SIZE</code>, <code>2 *128 * PAGE_SIZE</code>，剩下256,512的页块都没有了因此推测，导致这个问题出现的时候，该机器的内存碎片很多，当某个应用执行时，在xfs的申请内存中有这种连续的大块的内存申请的操作的请求。</p>
<p>比如：6000: map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL | KM_NOFS); 就会导致内存一直分配不到。</p>
<p>例如：执行 <code>docker ps</code>，<code>docker exec</code>这些命令时，会一直阻塞在 <code>kmem_alloc</code> 的循环中，反复申请内存，由于内存碎片没有被组合，因此就一直申请不到，执行这些命令也会卡住，这也就验证了执行某些命令如<code>ls</code>、<code>ssh</code>都不会失败(因为需要内存的 <code>PAGE</code> 不是那么大)。</p>
<h3 id="临时解决方法："><a href="#临时解决方法：" class="headerlink" title="临时解决方法："></a>临时解决方法：</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">echo 1 &gt; &#x2F;proc&#x2F;sys&#x2F;vm&#x2F;drop_caches</span><br></pre></td></tr></table></figure>

<p>上述命令操作会把碎片化的 <code>PAGE</code> 重新分配，之后在申请大块的PAGE内存就可以申请到，不阻塞了。</p>
<h3 id="永久解决方法："><a href="#永久解决方法：" class="headerlink" title="永久解决方法："></a>永久解决方法：</h3><p>优化内核参数：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"># 保留1G空闲内存，达到该值，触发内存回收</span><br><span class="line">$ cat &gt;&gt; &#x2F;etc&#x2F;sysctl.conf &lt;&lt;EOF</span><br><span class="line">vm.min_free_kbytes &#x3D; 1048576</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">#立即生效</span><br><span class="line">$ sysctl -p</span><br></pre></td></tr></table></figure>

<h3 id="什么是-overcommit-or-oom-问题"><a href="#什么是-overcommit-or-oom-问题" class="headerlink" title="什么是 overcommit or oom 问题"></a>什么是 overcommit or oom 问题</h3><p>Linux对大部分申请内存的请求都回复”yes”，以便能跑更多更大的程序，因为申请内存后，并不会马上使用内存，这种技术叫做 <code>Overcommit</code>。</p>
<p>当linux发现内存不足时，会发生OOM killer(OOM=out-of-memory)，它会选择杀死一些进程(用户态进程，不是内核线程)，以便释放内存。</p>
<p>当 oom-killer 发生时，linux会选择杀死哪些进程？选择进程的函数是oom_badness函数(在mm/oom_kill.c中)，该函数会计算每个进程的点数(0~1000)，点数越高，这个进程越有可能被杀死。</p>
<p>每个进程的点数跟 <code>oom_score_adj</code> 有关，而且 <code>oom_score_adj</code> 可以被设置(-1000最低，1000最高)。</p>
<h3 id="内核参数-overcommit-memory-它是内存分配策略"><a href="#内核参数-overcommit-memory-它是内存分配策略" class="headerlink" title="内核参数 overcommit_memory, 它是内存分配策略"></a>内核参数 overcommit_memory, 它是内存分配策略</h3><p><code>可选值</code>：0、1、2。</p>
<ul>
<li><code>0</code>：表示内核将检查是否有足够的可用内存供应用进程使用；如果有足够的可用内存，内存申请允许；否则，内存申请失败，并把错误返回给应用进程。</li>
<li><code>1</code>：表示内核允许分配所有的物理内存，而不管当前的内存状态如何。</li>
<li><code>2</code>：表示内核允许分配超过所有物理内存和交换空间总和的内存。</li>
</ul>
<h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><ul>
<li><a target="_blank" rel="noopener" href="https://www.mawenbao.com/research/linux-ate-my-memory.html">https://www.mawenbao.com/research/linux-ate-my-memory.html</a></li>
<li><a target="_blank" rel="noopener" href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/performance_tuning_guide/s-memory-tunables">https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/performance_tuning_guide/s-memory-tunables</a></li>
<li><a target="_blank" rel="noopener" href="http://blog.51yip.com/nosql/1776.html">http://blog.51yip.com/nosql/1776.html</a></li>
<li><a target="_blank" rel="noopener" href="http://linuxperf.com/?p=102">http://linuxperf.com/?p=102</a></li>
</ul>
<blockquote>
<ul>
<li>案例一原文出处：<a target="_blank" rel="noopener" href="http://blog.atime.me/research/linux-ate-my-memory.html">http://blog.atime.me/research/linux-ate-my-memory.html</a></li>
<li>案例二原文出处：<a target="_blank" rel="noopener" href="https://www.cnblogs.com/beilong/p/8192676.html">https://www.cnblogs.com/beilong/p/8192676.html</a></li>
</ul>
</blockquote>
 
      <!-- reward -->
      
      <div id="reword-out">
        <div id="reward-btn">
          打赏
        </div>
      </div>
      
    </div>
    

    <!-- copyright -->
    
    <div class="declare">
      <ul class="post-copyright">
        <li>
          <i class="ri-copyright-line"></i>
          <strong>版权声明： </strong>
          
          本博客所有文章除特别声明外，著作权归作者所有。转载请注明出处！
          
        </li>
      </ul>
    </div>
    
    <footer class="article-footer">
       
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=http://example.com/2020/11/11/linux/%E5%88%86%E4%BA%ABLinux%E5%86%85%E5%AD%98%E5%8D%A0%E7%94%A8%E5%87%A0%E4%B8%AA%E6%A1%88%E4%BE%8B/" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>  
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/linux/" rel="tag">linux</a></li></ul>

    </footer>
  </div>

   
  <nav class="article-nav">
    
      <a href="/2020/11/11/linux/%E4%BB%8E%20lsof%20%E5%BC%80%E5%A7%8B%EF%BC%8C%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%20Linux%20%E8%99%9A%E6%8B%9F%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            从 lsof 开始，深入理解 Linux 虚拟文件系统.md
          
        </div>
      </a>
    
    
      <a href="/2020/11/11/linux/%E5%88%A9%E7%94%A8%20Shell%20%E8%84%9A%E6%9C%AC%E5%AE%9E%E7%8E%B0%E9%82%AE%E4%BB%B6%E7%9B%91%E6%8E%A7%20Linux%20%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%86%85%E5%AD%98/" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">利用 Shell 脚本实现邮件监控 Linux 系统的内存.md</div>
      </a>
    
  </nav>

   
<!-- valine评论 -->
<div id="vcomments-box">
  <div id="vcomments"></div>
</div>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/valine@1.4.14/dist/Valine.min.js"></script>
<script>
  new Valine({
    el: "#vcomments",
    app_id: "",
    app_key: "",
    path: window.location.pathname,
    avatar: "monsterid",
    placeholder: "给我的文章加点评论吧~",
    recordIP: true,
  });
  const infoEle = document.querySelector("#vcomments .info");
  if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0) {
    infoEle.childNodes.forEach(function (item) {
      item.parentNode.removeChild(item);
    });
  }
</script>
<style>
  #vcomments-box {
    padding: 5px 30px;
  }

  @media screen and (max-width: 800px) {
    #vcomments-box {
      padding: 5px 0px;
    }
  }

  #vcomments-box #vcomments {
    background-color: #fff;
  }

  .v .vlist .vcard .vh {
    padding-right: 20px;
  }

  .v .vlist .vcard {
    padding-left: 10px;
  }
</style>

 
     
</article>

</section>
      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2015-2020
        <i class="ri-heart-fill heart_icon"></i> TzWind
      </li>
    </ul>
    <ul>
      <li>
        
        
        
        由 <a href="https://hexo.io" target="_blank">Hexo</a> 强力驱动
        <span class="division">|</span>
        主题 - <a href="https://github.com/Shen-Yu/hexo-theme-ayer" target="_blank">Ayer</a>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>访问人数:<span id="busuanzi_value_site_uv"></span></s>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>浏览次数:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s9.cnzz.com/z_stat.php?id=1278069914&amp;web_id=1278069914'></script>
        
      </li>
    </ul>
  </div>
</footer>
      <div class="float_btns">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

      </div>
    </main>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="/images/ayer-side.svg" alt="Hexo"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" target="_blank" rel="noopener" href="http://www.baidu.com">百度</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/friends">友链</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/2019/about">关于我</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="搜索">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <script>
      if (window.matchMedia("(max-width: 768px)").matches) {
        document.querySelector('.content').classList.remove('on');
        document.querySelector('.sidebar').classList.remove('on');
      }
    </script>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    
  </div>
</div>
    
<script src="/js/jquery-2.0.3.min.js"></script>


<script src="/js/lazyload.min.js"></script>

<!-- Tocbot -->


<script src="/js/tocbot.min.js"></script>

<script>
  tocbot.init({
    tocSelector: '.tocbot',
    contentSelector: '.article-entry',
    headingSelector: 'h1, h2, h3, h4, h5, h6',
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer: 'main',
    positionFixedSelector: '.tocbot',
    positionFixedClass: 'is-position-fixed',
    fixedSidebarOffset: 'auto'
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>

<!-- ImageViewer -->

<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.min.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script>

<!-- MathJax -->

<!-- Katex -->

<!-- busuanzi  -->


<script src="/js/busuanzi-2.3.pure.min.js"></script>


<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->

<!-- CodeCopy -->


<link rel="stylesheet" href="/css/clipboard.css">

<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>


<!-- CanvasBackground -->


    
  </div>
</body>

</html>